﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

#region User add using scop
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
#endregion

namespace org.alex.edss
{
    public class Connector
    {
        #region Connector private members

        private Socket sock;

        private bool servermode;

        private SocketAsyncEventArgs syncArgs;

        private SocketAsyncEventArgs readArgs;

        private SocketAsyncEventArgs writeArgs;

        private int bufferSize;

        private byte[] buffer;

        public int Offset
        {
            get;
            set;
        }

        #endregion

        #region Connector Events

        public event ConnectionEventHandler ConnectSuccessfull;

        public event ConnectionEventHandler ConnectError;

        public event ConnectionEventHandler OnRead;

        public event ConnectionEventHandler ReadComplete;

        public event ConnectionEventHandler WriteComplete;

        public event ConnectionEventHandler OperationError;

        #endregion

        /// <summary>
        /// Constructor to create a new socket object as client binding in local ip
        /// </summary>
        public Connector(string ip,int port,int buffersize)
        {
            try
            {
                servermode = false;
                bufferSize = buffersize;
                buffer = new byte[buffersize];
                sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
                sock.Bind(
                    new IPEndPoint(
                                    IPAddress.Parse(ip), port
                                    )
                        );
                syncArgs = new SocketAsyncEventArgs();
                syncArgs.Completed += new EventHandler<SocketAsyncEventArgs>(syncArgs_Completed);
                readArgs = new SocketAsyncEventArgs();
                writeArgs = new SocketAsyncEventArgs();
                SetEvent();
            }
            catch (Exception ex)
            {
                if (ConnectError != null)
                {
                    ConnectError(this, ex);
                }
            }
        }
        public Connector(Socket AcceptSocket,SocketAsyncEventArgs readarg,SocketAsyncEventArgs writearg,byte[] SessionBuffer)
        {
            try
            {
                servermode = true;
                sock = AcceptSocket;
                readArgs = readarg;
                writeArgs = writearg;
                buffer = SessionBuffer;
                bufferSize = SessionBuffer.Length;
                SetEvent();
            }
            catch (Exception ex)
            {
                if (ConnectError != null)
                {
                    ConnectError(this, ex);
                }
            }
        }

        private void SetEvent()
        {
            readArgs.Completed += new EventHandler<SocketAsyncEventArgs>(readArgs_Completed);
            writeArgs.Completed += new EventHandler<SocketAsyncEventArgs>(writeArgs_Completed);
            readArgs.SetBuffer(buffer, 0, bufferSize);
        }

        void writeArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
            try
            {
                //throw new NotImplementedException();
                if (e.SocketError == SocketError.Success)
                {
                    if (e.BytesTransferred > 0)
                    {
                        if (WriteComplete != null)
                        {
                            WriteComplete(this, null);
                        }
                    }
                }
                else
                {
                    if (OperationError != null)
                    {
                        OperationError(this, "write error");
                    }
                }
            }
            catch (Exception ex)
            {
                if (OperationError != null)
                {
                    OperationError(this, ex.Message);
                }
            }
        }

        void readArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
            //throw new NotImplementedException();
            try
            {
                Offset = e.BytesTransferred;
                if (e.SocketError == SocketError.Success)
                {
                    if (e.BytesTransferred > 0)
                    {
                        if (OnRead != null)
                        {
                            OnRead(this, buffer);
                        }
                        if (e.BytesTransferred < bufferSize)
                        {
                            if (ReadComplete != null)
                            {
                                ReadComplete(this, null);
                            }
                        }
                    }
                    else
                    {
                        if (ReadComplete != null)
                        {
                            ReadComplete(this, null);
                        }
                    }
                }
                else
                {
                    if (OperationError != null)
                    {
                        OperationError(this, "SocketError when Receive async complete:" + e.SocketError.ToString());
                    }
                }
            }
            catch (Exception ex)
            {
                if (OperationError != null)
                {
                    OperationError(this, ex);
                }
            }

        }

        public void connect(string ip, int port)
        {
            try
            {
                if (servermode)
                {
                    return;
                }
                else
                {
                    syncArgs.RemoteEndPoint = new IPEndPoint(
                        IPAddress.Parse(ip), port);
                    bool AsyncResult = sock.ConnectAsync(syncArgs);
                    if (!AsyncResult)
                    {
                        if (ConnectError != null)
                        {
                            ConnectError(this, "ConnectAsync return false");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (ConnectError != null)
                {
                    ConnectError(this, ex);
                }
            }
        }

        void syncArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
            try
            {
                if (e.SocketError == SocketError.Success)
                {
                    if (ConnectSuccessfull != null)
                    {
                        ConnectSuccessfull(this, null);
                    }
                }
                else
                {
                    if (ConnectError != null)
                    {
                        ConnectError(this, "SocketError when Connect async complete:" + e.SocketError.ToString());
                    }
                }
            }
            catch (Exception ex)
            {
                if (ConnectError != null)
                {
                    ConnectError(this, ex);
                }
            }
        }



        public void Read()
        {
            try
            {
                bool AsyncResult = sock.ReceiveAsync(readArgs);
                if (!AsyncResult)
                {
                    if (OperationError != null)
                    {
                        OperationError(this, "ReadAsync return false");
                    }
                }
            }
            catch (Exception ex)
            {
                if (OperationError != null)
                {
                    OperationError(this, ex);
                }
            }
        }
        public void Write(byte[] data)
        {
            try
            {
                writeArgs.SetBuffer(data, 0, data.Length);
                bool AsyncResult = sock.SendAsync(writeArgs);
                if (!AsyncResult)
                {
                    if (OperationError != null)
                    {
                        OperationError(this, "Write Error when calling SendAsync");
                    }
                }
            }
            catch (Exception ex)
            {
                if (OperationError != null)
                {
                    OperationError(this, ex);
                }
            }
        }

        public void Disconnect()
        {
            try
            {
                sock.Shutdown(SocketShutdown.Both);
                sock.Close();
            }
            catch { }
        }


    }
}
